<!DOCTYPE html>
<html lang="zh-Hans">
<head>

    <!--[if lt IE 9]>
        <style>body {display: none; background: none !important} </style>
        <meta http-equiv="Refresh" Content="0; url=//outdatedbrowser.com/" />
    <![endif]-->

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="format-detection" content="telephone=no" />
<meta name="author" content="FreeShow" />



<meta property="og:type" content="article">
<meta property="og:title" content="Java之lambda表达式">
<meta property="og:url" content="https://freeshow.github.io/Programming/Java/Java之lambda表达式/index.html">
<meta property="og:site_name" content="FreeShow">
<meta property="og:updated_time" content="2017-03-28T08:06:44.541Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java之lambda表达式">

<link rel="apple-touch-icon" href= "/apple-touch-icon.png">


    <link rel="alternate" href="/atom.xml" title="FreeShow" type="application/atom+xml">



    <link rel="shortcut icon" href="/favicon.ico">



    <link href="//cdn.bootcss.com/animate.css/3.5.1/animate.min.css" rel="stylesheet">



    <link href="//cdn.bootcss.com/fancybox/2.1.5/jquery.fancybox.min.css" rel="stylesheet">



    <script src="//cdn.bootcss.com/pace/1.0.2/pace.min.js"></script>
    <link href="//cdn.bootcss.com/pace/1.0.2/themes/blue/pace-theme-minimal.css" rel="stylesheet">


<link rel="stylesheet" href="/css/style.css">



<link href="//cdn.bootcss.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet">


<title>Java之lambda表达式 | FreeShow</title>

<script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="//cdn.bootcss.com/clipboard.js/1.5.10/clipboard.min.js"></script>

<script>
    var yiliaConfig = {
        fancybox: true,
        animate: true,
        isHome: false,
        isPost: true,
        isArchive: false,
        isTag: false,
        isCategory: false,
        fancybox_js: "//cdn.bootcss.com/fancybox/2.1.5/jquery.fancybox.min.js",
        scrollreveal: "//cdn.bootcss.com/scrollReveal.js/3.1.4/scrollreveal.min.js",
        search: true
    }
</script>


    <script>
        yiliaConfig.jquery_ui = [true, "//cdn.bootcss.com/jqueryui/1.10.4/jquery-ui.min.js", "//cdn.bootcss.com/jqueryui/1.10.4/css/jquery-ui.min.css"];
    </script>



    <script> yiliaConfig.rootUrl = "\/";</script>






</head>
<body>
  <div id="container">
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
    <header id="header" class="inner">
        <a href="/" class="profilepic">
            <img src="/img/avatar.png" class="animated zoomIn">
        </a>
        <hgroup>
          <h1 class="header-author"><a href="/">FreeShow</a></h1>
        </hgroup>

        
        <p class="header-subtitle">在追求艺术的道路上狂奔</p>
        

        
            <form id="search-form">
            <input type="text" id="local-search-input" name="q" placeholder="search..." class="search form-control" autocomplete="off" autocorrect="off" searchonload="false" />
            <i class="fa fa-times" onclick="resetSearch()"></i>
            </form>
            <div id="local-search-result"></div>
            <p class='no-result'>No results found <i class='fa fa-spinner fa-pulse'></i></p>
        


        
            <div id="switch-btn" class="switch-btn">
                <div class="icon">
                    <div class="icon-ctn">
                        <div class="icon-wrap icon-house" data-idx="0">
                            <div class="birdhouse"></div>
                            <div class="birdhouse_holes"></div>
                        </div>
                        <div class="icon-wrap icon-ribbon hide" data-idx="1">
                            <div class="ribbon"></div>
                        </div>
                        
                        <div class="icon-wrap icon-link hide" data-idx="2">
                            <div class="loopback_l"></div>
                            <div class="loopback_r"></div>
                        </div>
                        
                        
                        <div class="icon-wrap icon-me hide" data-idx="3">
                            <div class="user"></div>
                            <div class="shoulder"></div>
                        </div>
                        
                    </div>
                    
                </div>
                <div class="tips-box hide">
                    <div class="tips-arrow"></div>
                    <ul class="tips-inner">
                        <li>菜单</li>
                        <li>标签</li>
                        
                        <li>友情链接</li>
                        
                        
                        <li>关于我</li>
                        
                    </ul>
                </div>
            </div>
        

        <div id="switch-area" class="switch-area">
            <div class="switch-wrap">
                <section class="switch-part switch-part1">
                    <nav class="header-menu">
                        <ul>
                        
                            <li><a href="/">主页</a></li>
                        
                            <li><a href="/archives/">所有文章</a></li>
                        
                            <li><a href="/tags/">标签云</a></li>
                        
                            <li><a href="/about/">关于我</a></li>
                        
                        </ul>
                    </nav>
                    <nav class="header-nav">
                        <ul class="social">
                            
                                <a class="fa Email" href="mailto:877646746@qq.com" title="Email"></a>
                            
                                <a class="fa GitHub" href="http://github.com/freeshow" title="GitHub"></a>
                            
                                <a class="fa 新浪微博" href="http://weibo.com/freeshowself" title="新浪微博"></a>
                            
                                <a class="fa CSDN" href="http://blog.csdn.net/u011026329" title="CSDN"></a>
                            
                        </ul>
                    </nav>
                </section>
                
                
                <section class="switch-part switch-part2">
                    <div class="widget tagcloud" id="js-tagcloud">
                        <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android/">Android</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/C/">C</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Crawler/">Crawler</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Hadoop/">Hadoop</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Hexo/">Hexo</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java/">Java</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/">Linux</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Python/">Python</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/SIP/">SIP</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Scala/">Scala</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Shell/">Shell</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spark/">Spark</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Tools/">Tools</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/WebRTC/">WebRTC</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/XMPP/">XMPP</a></li></ul>
                    </div>
                </section>
                
                
                
                <section class="switch-part switch-part3">
                    <div id="js-friends">
                    
                      <a class="main-nav-link switch-friends-link" href="https://hexo.io">Hexo</a>
                    
                      <a class="main-nav-link switch-friends-link" href="https://github.com/freeshow">GitHub</a>
                    
                      <a class="main-nav-link switch-friends-link" href="http://freeshow.github.io/">FreeShow</a>
                    
                    </div>
                </section>
                

                
                
                <section class="switch-part switch-part4">
                
                    <div id="js-aboutme">我是一个喜欢无拘无束、追求自由、热爱分享的小小小码农！</div>
                </section>
                
            </div>
        </div>
    </header>                
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
      <div class="overlay">
          <div class="slider-trigger"></div>
          <h1 class="header-author js-mobile-header hide"><a href="/" title="回到主页">FreeShow</a></h1>
      </div>
    <div class="intrude-less">
        <header id="header" class="inner">
            <a href="/" class="profilepic">
                <img src="/img/avatar.png" class="animated zoomIn">
            </a>
            <hgroup>
              <h1 class="header-author"><a href="/" title="回到主页">FreeShow</a></h1>
            </hgroup>
            
            <p class="header-subtitle">在追求艺术的道路上狂奔</p>
            
            <nav class="header-menu">
                <ul>
                
                    <li><a href="/">主页</a></li>
                
                    <li><a href="/archives/">所有文章</a></li>
                
                    <li><a href="/tags/">标签云</a></li>
                
                    <li><a href="/about/">关于我</a></li>
                
                <div class="clearfix"></div>
                </ul>
            </nav>
            <nav class="header-nav">
                        <ul class="social">
                            
                                <a class="fa Email" target="_blank" href="mailto:877646746@qq.com" title="Email"></a>
                            
                                <a class="fa GitHub" target="_blank" href="http://github.com/freeshow" title="GitHub"></a>
                            
                                <a class="fa 新浪微博" target="_blank" href="http://weibo.com/freeshowself" title="新浪微博"></a>
                            
                                <a class="fa CSDN" target="_blank" href="http://blog.csdn.net/u011026329" title="CSDN"></a>
                            
                        </ul>
            </nav>
        </header>                
    </div>
    <link class="menu-list" tags="标签" friends="友情链接" about="关于我"/>
</nav>
      <div class="body-wrap"><article id="post-Programming/Java/Java之lambda表达式" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/Programming/Java/Java之lambda表达式/" class="article-date">
      <time datetime="2016-07-23T15:06:29.000Z" itemprop="datePublished">2016-07-23</time>
</a>


    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Java之lambda表达式
    </h1>
  

      </header>
      
      <div class="article-info article-info-post">
        
    <div class="article-category tagcloud">
    <a class="article-category-link" href="/categories/编程语言/">编程语言</a>
    </div>


        
    <div class="article-tag tagcloud">
        <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java/">Java</a></li></ul>
    </div>

        <div class="clearfix"></div>
      </div>
      
    
    <div class="article-entry" itemprop="articleBody">
      
          
        <p><excerpt in="" index="" |="" 首页摘要=""><br><a id="more"></a></excerpt></p>
<the rest="" of="" contents="" |="" 余下全文="">

<p><strong>15.1 lambda表达式简介</strong></p>
<pre><code>对于理解lambda表达式的Java实现，有两个结果十分关键。第一个就是lambda表达式自身，第二个是函数式接口。

lambda表达式本质上就是一个匿名(即未命名的方法)。但是这个方法不能独立执行的，而是用于实现由函
数式接口定义的一个方法。因此，lambda表达式会导致产生一个匿名类。lambda表达式也常被称为闭包。

函数式接口是仅包含一个抽象方法的接口。一般来说，这个方法指明了接口的目标用途。因此，函数式接口通常表示单个动作。例如，标准接口Runnable是一个函数式接口，因为它只定义了一个方法run().因此，run()定义了Runnable的动作。此外，函数式接口定义了lambda表达式的目标类型。特别注意：lambda表达式只能用于其目标类型已经被指定的上下文中。另外，函数式接口有时候被称为SAM类型，意思是单抽象方法(Single Abstract Method)。 

注意：
函数式接口可以定义Object定义的任何公有方法，例如equals()，而不影响其作为&quot;函数式接口&quot;的状态。Object的公有方法被视为函数式接口的隐式成员，因为函数式接口的实例会默认自动实现它们。
</code></pre><p><strong>15.1.1 lambda表达式的基础知识</strong></p>
<pre><code>lambda表达式在Java语言中引入了一个新的语法元素和操作符。这个操作符是-&gt;,有时候被称为lambda操作符或箭头操作符。它将lambda表达式分成两部分。左侧指定了lambda表达式所需要的所有参数(如果不需要参数，则使用空的参数列表)。右侧指定了lambda体，即lambda表达式要执行的动作。在用语言描述时，可以把-&gt;表达成&quot;成了&quot;或&quot;进入&quot;。

Java定义了两种lambda体。第一种包含单独一个表达式，另一种包含一个代码块。

(1)lambda体包含单独一个表达式

首先，看一个最简单的lambda表达式。它的计算结果是一个常量值，如下所示：

()-&gt;123.45

这个lambda表达式没有形参，所以参数列表为空。它返回常量值123.45.因此，这个表达式的作用类似于下面的方法：

double myMeth(){return 123.45;}

当然，lambda表达式定义的方法没有名称。

下面给出一个更有意思的表达式：

()-&gt;Math.random()*100

这个lambda表达式使用Math.random()获得一个随机数，将其乘以100，然后返回结果。这个lambda表达式也不需要参数。

当lambda表达式需要参数时，需要在操作符左侧的参数列表中加以指定。下面是一个简单的例子：

(n)-&gt;(n%2)==0

如果参数n的值是偶数，这个lambda表达式会返回true。尽管可以显示指定参数的类型，例如本例中的n，但是通常不需要这么做，因为很多时候，参数的类型是可以推断出来的。与命名方法一样，lambda表达式可以指定需要用到的任意参数的数量。
</code></pre><p><strong>15.1.2 函数式接口</strong> </p>
<pre><code>函数式接口是指仅定义了一个抽象方法的接口。从JDK8开始，可以为接口声明的方法指定默认行为，即所谓的默认方法。如今，只有当没有指定默认方法实现时，接口方法才是抽象方法。因为没有指定默认实现的接口方法隐式的是抽象方法，所以没有必要使用abstract修饰符(如果愿意的话，也可以指定该修饰符)。

下面是函数式接口的例子：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">interface MyNumber</div><div class="line">&#123;</div><div class="line">	double getValue();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>在本例中，getValue()方法隐式的是抽象方法，并且是MyNumber定义的唯一方法。因此，MyNumber是一个函数式接口，其功能由getValue()定义。

如前所述，lambda表达式不是独立执行的，而是构成了一个函数式接口定义的抽象方法的实现，该函数式接口定义了它的目标类型。结果，只有在定义了lambda表达式的目标类型的上下文中，才能使用该表达式。当把一个lambda表达式赋给一个函数式接口的引用时，就创建了这样的上下文。

下面通过一个例子来说明如何在参数上下文中使用lambda表达式。首先，声明对函数式接口MyNumber的一个引用：

MyNumber myNum;

接下来，将一个lambda表达式赋值给该接口引用：

myNum = ()-&gt;123.45

当目标类型上下文中出现lambda表达式时，就会自动创建实现了函数式接口的一个类的实例(类似于匿名类)，函数式接口声明的抽象方法的行为由lambda表达式定义。当通过目标调用该方法时，就会执行lambda表达式。因此，lambda表达式成了getValue()方法的实现。因此，下面的代码将显示123.45：

System.out.println(myNum.getValue());

因为赋给myNum的lambda表达式返回值123.45，所以调用getValue()方法时返回的值也是123.45。

为了在目标类型上下文中使用lambda表达式，抽象方法的类型和lambda表达式的类型必须兼容。例如，如果抽象方法指定了两个int类型的参数，那么lambda表达式也必须执行两个参数，其类型要么被显示指定为int类型，要么在上下文中可以被隐式的推断为int类型。总的来说，lambda表达式的参数的类型和数量必须与方法的参数兼容；返回类型必须兼容；并且lambda表达式可能抛出的异常必须能被方法接受。
</code></pre><p><strong>15.1.3 几个lambda表达式示例</strong></p>
<pre><code>(1)
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line">//函数式接口 </div><div class="line">interface MyNumber</div><div class="line">&#123;</div><div class="line">	double getValue();</div><div class="line">&#125;</div><div class="line"></div><div class="line">class lambdaDemo</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		MyNumber myNum;</div><div class="line">		</div><div class="line">		myNum = ()-&gt;123.45;</div><div class="line">		System.out.println(&quot;A fixed value: &quot;+myNum.getValue());</div><div class="line">		</div><div class="line">		myNum = ()-&gt;Math.random()*100;</div><div class="line">		System.out.println(&quot;A random value: &quot;+myNum.getValue());</div><div class="line">		</div><div class="line">		//lambda表达式的返回值类型与函数式接口中抽象函数的类型不匹配。</div><div class="line">	//	myNum = ()-&gt;&quot;123.03&quot;	//error! </div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>(2)带参数的lambda表达式：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">interface NumericTest</div><div class="line">&#123;</div><div class="line">	boolean test(int n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class lambdaDemo2</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		NumericTest isEven = (n)-&gt;(n%2)==0;</div><div class="line">		if(isEven.test(10)) System.out.println(&quot;10 is even&quot;);</div><div class="line">		if(!isEven.test(9)) System.out.println(&quot;9 is not even&quot;);</div><div class="line">		</div><div class="line">		NumericTest isNonNeg = (n)-&gt; n&gt;=0;</div><div class="line">		if(isNonNeg.test(1)) System.out.println(&quot;1 is non-negative&quot;);</div><div class="line">		if(!isNonNeg.test(-1)) System.out.println(&quot;-1 is negative&quot;);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>测试奇偶性的lambda表达式，如下所示：

NumericTest isEven = (n)-&gt;(n%2)==0;

注意，这里没有指定n的类型。相反，n的类型是从上下文中推断出来的。本例中，其类型是从NumericTest接口定义的test()方法的参数类型推断出来的，而该参数的类型是Int。在lambda表达式中，也可以显示指定参数的类型。例如，下面的写法也是合法的：

NumericTest isEven = (int n)-&gt;(n%2)==0;

如果lambda表达式只有一个参数，在操作符的左侧指定该参数时，没有必要使用括号扩住该参数的名称。例如下面的下法也是合法的：

NumericTest isEven = n-&gt;(n%2)==0;

(3)接受两个参数的lambda表达式：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">interface NumericTest2</div><div class="line">&#123;</div><div class="line">	boolean test(int n,int d);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class lambdaDemo3</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		//测试一个数字是否是另一个数字的因子。</div><div class="line">		NumericTest2 isFactor = (n,d) -&gt; (n%d)==0;</div><div class="line">		</div><div class="line">		if(isFactor.test(10,2)) System.out.println(&quot;2 is a factor of 10&quot;);</div><div class="line">		if(!isFactor.test(10,3)) System.out.println(&quot;3 is not a factor of 10&quot;);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>注意指定这种lambda表达式的方法：

NumericTest2 isFactor = (n,d) -&gt; (n%d)==0;

两个参数n和d在参数列表中指定，并使用逗号分隔开。可以把这个例子推而广之。每当需要一个以上的参数时，就在lambda操作符的左侧，使用一个带括号的参数列表指定参数，参数之间使用逗号分隔开。

对于lambda表达式中的多个参数，有一点十分重要：如果需要显示的声明一个参数的类型，那么必须为所有的参数声明类型。例如下面的代码是合法的：

NumericTest2 isFactor = (int n,int d) -&gt; (n%d)==0;

但下面的不合法：

NumericTest2 isFactor = (int n,d) -&gt; (n%d)==0;
</code></pre><p><strong>15.2 块lambda表达式</strong></p>
<pre><code>前面例子中显示的lambda体只包含单个表达式。这种类型的lambda体被称为表达式体，具有表达式体的lambda表达式有时被称为表达式lambda。在表达式体重，操作符右侧的代码必须包含单独一个表达式。尽管表达式lambda十分有用，但是有时候会要求使用一个以上的表达式。为了处理这种情况，Java支持另外一种类型的lambda表达式，其中操作符右侧的代码可以由一个代码块构成，其中可以包含多条语句。这种类型的lambda体被称为块体。具有块体的lambda表达式有时候被称为块lambda。

块lambda表达式扩展了lambda表达式内部可以处理的操作类型，因为它允许lambda体包含多条语句。例如，在lambda块中，可以声明变量、使用循环、指定if和switch语句、创建嵌套代码块等。创建块lambda很容易，只需要使用花括号包围lambda体，就像创建其他语句一样。

除了允许多条语句，块lambda的使用方法与刚才讨论过的表达式lambda十分类似。但是，也有一个重要区别：在块lambda中必须显示使用return语句来返回值。必须这么做，因为块lambda体代表的不是一个单独的表达式。

下面的例子是使用块lambda来计算并返回一个int类型值的阶乘：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">interface NumericFunc</div><div class="line">&#123;</div><div class="line">	inf func(int n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class BlockLambdaDemo</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		NumericFunc factorial = (n)-&gt;</div><div class="line">		&#123;</div><div class="line">			int result = 1;</div><div class="line">			</div><div class="line">			for(int i=1; i&lt;=n; i++)</div><div class="line">			&#123;</div><div class="line">				result = i*result;</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			return result;</div><div class="line">		&#125;;</div><div class="line">		</div><div class="line">		System.out.println(&quot;The factorial of 3 is &quot;+factorial.func(3));</div><div class="line">		System.out.println(&quot;The factorial of 5 is &quot;+factorial.func(5));</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>注意：
当lambda表达式中出现return语句时，只是从lambda体返回，而不会导致包围lambda体的方法返回。
</code></pre><p><strong>15.3 泛型函数式接口</strong></p>
<pre><code>lambda表达式自身不能指定类型参数。因此，lambda表达式不能是泛型(当然，由于存在类型推断，所有lambda表达式都展现出了一些类似于泛型的特征)。然而，与lambda表达式关联的函数式接口可以泛型。此时，lambda表达式的目标类型部分由声明函数式接口引用时指定的参数类型决定。

例如：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line">interface SomeFunc&lt;T&gt;</div><div class="line">&#123;</div><div class="line">	T func(T t);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class GenericFunctionalInterfaceDemo</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		SomeFunc&lt;String&gt; reverse = (str)-&gt;</div><div class="line">		&#123;</div><div class="line">			int i;</div><div class="line">			String result = &quot;&quot;;</div><div class="line">			</div><div class="line">			for(i = str.length()-1; i&gt;=0; i--)</div><div class="line">			&#123;</div><div class="line">				result += str.charAt(i);</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			return result;</div><div class="line">		&#125;;</div><div class="line">		</div><div class="line">		System.out.println(&quot;lambda reserved is &quot;+reverse.func(&quot;lambda&quot;));</div><div class="line">		</div><div class="line">		SomeFunc&lt;Integer&gt; factorial = (n)-&gt;</div><div class="line">		&#123;</div><div class="line">			int result = 1;</div><div class="line">			</div><div class="line">			for(int i=1; i&lt;=n; i++)</div><div class="line">			&#123;</div><div class="line">				result = result*i;</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			return result;</div><div class="line">		&#125;;</div><div class="line">		</div><div class="line">		System.out.println(&quot;The factorial of 3 is &quot;+factorial.func(3));</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
lambda reserved is adbmal
The factorial of 3 is 6

其中，T指定了func()函数的返回类型和参数类型。这意味着它与任何接收一个参数，并返回一个相同类型的值的lambda表达式兼容。

SomeFunc接口用于提供对两种不同类型的lambda表达式的引用。第一种表达式使用String类型，第二种表达式使用Integer类型。因此，同一个函数式接口可以用于reserve lambda表达式和factorial lambda表达式。区别仅在于传递给SomeFunc的参数类型。
</code></pre><p><strong>15.4 作为参数传递lambda表达式</strong></p>
<pre><code>为了将lambda表达式作为参数传递，接收lambda表达式的参数的类型必须是与该lambda表达式兼容的函数式接口的类型。例如：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div></pre></td><td class="code"><pre><div class="line">//Use lambda expressions as an argument to method</div><div class="line"></div><div class="line">interface StringFunc</div><div class="line">&#123;</div><div class="line">	String func(String n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class lambdasAsArgumentsDemo</div><div class="line">&#123;</div><div class="line">	static String stringOp(StringFunc sf,String s)</div><div class="line">	&#123;</div><div class="line">		return sf.func(s);</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		String inStr = &quot;lambda add power to java&quot;;</div><div class="line">		String outStr;</div><div class="line">		</div><div class="line">		System.out.println(&quot;Here is input string: &quot;+inStr);</div><div class="line">		</div><div class="line">		outStr = stringOp((str)-&gt;str.toUpperCase(),inStr);</div><div class="line">		System.out.println(&quot;The string in uppercase: &quot;+outStr);</div><div class="line">		</div><div class="line">		outStr = stringOp((str)-&gt;</div><div class="line">		&#123;</div><div class="line">			String result = &quot;&quot;;</div><div class="line">			int i;</div><div class="line">			</div><div class="line">			for(i=0; i&lt;str.length(); i++)</div><div class="line">			&#123;</div><div class="line">				if(str.charAt(i) != &apos;&apos;)</div><div class="line">				&#123;</div><div class="line">					result += str.charAt(i);</div><div class="line">				&#125;</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			return result;</div><div class="line">		&#125;,inStr);</div><div class="line">		System.out.println(&quot;The string with spaces removed: &quot;+outStr);</div><div class="line">		</div><div class="line">		//当块lambda看上去特别长，不适合嵌入到方法的调用中时，很容易把块lambda赋给一个函数式接口变量.</div><div class="line">		//然后，可以简单地把该引用传递给方法。</div><div class="line">		StringFunc reverse = (str)-&gt;</div><div class="line">		&#123;</div><div class="line">			String result = &quot;&quot;;</div><div class="line">			int i;</div><div class="line">			</div><div class="line">			for(i=str.length()-1; i&gt;=0; i--)</div><div class="line">			&#123;</div><div class="line">				result += str.charAt(i);</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			result result;</div><div class="line">		&#125;;</div><div class="line">		System.out.println(&quot;The string reserved: &quot;+stringOp(reverse,inStr));</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
Here is input string: lambda add power to java
The string in uppercase: LAMBDAS ADD POWER TO JAVA 
The string with spaces removed: lambdaaddpowertojava
The string reserved: avaJ ot rewop dda sadbmal

在该程序中，首先注意stringOp()方法。它有两个参数，第一个参数的类型是StringFunc,而StringFunc是一个函数式接口。因此，这个参数可以接受对任何StringFunc实例的引用，包括由lambda表达式创建的实例。stringOp的第二个参数是String类型，也就是要操作的字符串。

接下来，注意对stringOp()的第一次调用，如下所示：

outStr = stringOp((str)-&gt;str.uppercase(),inStr);

这里，传递了一个简单的表达式lambda作为参数。这会创建函数式接口StringFunc的一个实例，并把对该实例的一个引用传递给stringOp()方法的第一个参数这就把嵌入在一个类实例中的lambda代码传递给了方法。目标类型上下文由参数的类型决定。因此lambda表达式与该类型兼容，调用是合法的。

当块lambda看上去特别长，不适合嵌入到方法的调用中时，很容易把块lambda赋给一个函数式接口变量，正如上面代码中那样。然后，可以简单地把该引用传递给方法。
</code></pre><p><strong>15.5 lambda表达式与异常</strong></p>
<pre><code>lambda表达式可以抛出异常。但是，如果抛出经检查的异常，该异常就必须与函数式接口的抽象方法的throws子句中列出的异常兼容。下面的例子演示了这个事实。它计算一个double数组的平均值。但是，如果传递了长度为0的数组，就会抛出自定义异常EmptyArrayException。从示例中可以看出，DoubleNumericArrayFunc函数式接口内声明的func()方法的throws子句中列出了此异常。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div></pre></td><td class="code"><pre><div class="line">interface DoubleNumericArrayFunc</div><div class="line">&#123;</div><div class="line">	double func(double[] n)throws EmptyArrayException;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class EmptyArrayException extends Exception</div><div class="line">&#123;</div><div class="line">	EmptyArrayException()</div><div class="line">	&#123;</div><div class="line">		super(&quot;Array Empty&quot;);</div><div class="line">	&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class lambdaExceptionDemo</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		double[] values = &#123;1.0, 2.0, 3.0, 4.0, 5.0&#125;;</div><div class="line">		</div><div class="line">		DoubleNumericArrayFunc average = (n)-&gt;</div><div class="line">		&#123;</div><div class="line">			double sum = 0;</div><div class="line">			</div><div class="line">			if(n.length == 0)</div><div class="line">			&#123;</div><div class="line">				throw new EmptyArrayException();</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			for(int i=0; i&lt;n.length; i++)</div><div class="line">			&#123;</div><div class="line">				sum += n[i];</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			return sum / n.length;</div><div class="line">		&#125;;</div><div class="line">		</div><div class="line">		System.out.println(&quot;The average is &quot;+average.func(values));</div><div class="line">		</div><div class="line">		//This causes an exception to be throw.</div><div class="line">		System.out.println(&quot;The average is &quot;+average.func(new double[0]));</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>对average.func()的第一次调用返回了值2.5。在第二次调用中，由于传递了一个长度为0的数组，EmptyArryException异常被抛出。记住，在func()方法中包含throws子句是必要的。如果不这么做，那么由于lambda表达式不在于func()兼容，程序将无法通过编译。

注意：
函数式接口DoubleNumericArrayFunc的func()方法指定的参数是数组。然而，lambda表达式的参数是n，而不是n[]。回忆一下，lambda表达式的参数类型将从目标上下文中推断得出。在这里，目标上下文是double[]，所以n的类型将会是double[]。没有必要指定n[](这么做也不合法)。将参数显示的声明为double[] n是合法的，但是在本例中这么做不会有什么好处。
</code></pre><p><strong>15.6 lambda表达式和变量捕获</strong></p>
<pre><code>在lambda表达式中，可以访问其外层作用域定义的变量。例如，lambda表达式可以使用其外层定义的实例或静态变量。lambda表达式也可以显示或隐式地访问this变量，该变量引用lambda表达式的外层类的调用的实例。因此，lambda表达式可以获取或设置其外层类的实例或静态变量的值，以及调用其外层类定义的方法。

但是，当lambda表达式使用其外层作用域定义的局部变量时，会产生一种特殊的情况，称为变量捕获。在这种情况下，lambda表达式只能使用实质上final的局部变量。实质上final的变量是指在第一次赋值以后，值不在发生变化的变量(即在后面的程序中没有改变变量的值)。没有必要显示的将这种变量声明为final，不过那样做也不是错误(外层作用域的this参数自动是实质上final变量，lambda表达式没有自己的this参数)。

lambda表达式不能修改外层作用域内的局部变量，理解这一点很重要。修改局部变量会移除其实质上的final状态，从而使捕获该变量变得不合法。

下面程序演示了实质上的final的局部变量和可变局部变量的区别。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line">interface MyFunc</div><div class="line">&#123;</div><div class="line">	int func(int n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class VarCapture</div><div class="line">&#123;</div><div class="line">	int num = 10;</div><div class="line">	</div><div class="line">	MyFunc mylambda = (n)-&gt;</div><div class="line">	&#123;</div><div class="line">		//This use of num is ok.It does not modify num.</div><div class="line">		int v = num + n;</div><div class="line">		</div><div class="line">		//Hower,the following is illegal because it attempts to modify the value of num.	</div><div class="line">//		num++;</div><div class="line"></div><div class="line">		return v;</div><div class="line">	&#125;;</div><div class="line">	</div><div class="line">	//The following line would also cause an error,because it would remove the effectively </div><div class="line">	//final status from num.</div><div class="line">//	num = 9;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>正如注释所指出的，num实质是final变量，所有可以在mylambda内使用。但是，如果修改了num，不管是在lambda表达式内还是表达式外，num就会丢失其实质上final的状态。这会导致发生错误，程序将无法通过编译。

需要重点强调，lambda表达式可以使用和修改调用其调用类的实例变量，只是不能使用其外层作用域内的局部变量，除非该变量实质上是final变量。
</code></pre><p><strong>15.7 方法引用</strong></p>
<pre><code>有一个重要的特性与lambda表达式相关，叫做方法引用。方法引用提供了一种引用而不执行方法的方式。这种特性与lambda表达式相关，因为它也需要由兼容的函数式接口构成的目标类型上下文。计算时，方法引用会创建函数式接口的一个实例。
</code></pre><p><strong>15.7.1 静态方法的方法引用</strong></p>
<pre><code>要创建静态方法引用，需要使用下面的一般语法：

className:methodName

注意： 
类名与方法名之间使用双冒号分隔开。::是JDK 8新增的一个分隔符，专门用于此目的。在于目标类型兼容的任何地方，都
可以使用这个方法的引用。

下面的程序演示了一个静态方法的引用：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line">interface StringFunc</div><div class="line">&#123;</div><div class="line">	String func(String n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class MyStringOps</div><div class="line">&#123;</div><div class="line">	static String strReverse(String str)</div><div class="line">	&#123;</div><div class="line">		String result = &quot;&quot;;</div><div class="line">		int i;</div><div class="line">		</div><div class="line">		for(i=str.length()-1; i&gt;=0; i--)</div><div class="line">		&#123;</div><div class="line">			result += str.charAt(i);</div><div class="line">		&#125;</div><div class="line">		</div><div class="line">		return result;</div><div class="line">	&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class MethodRefDemo</div><div class="line">&#123;</div><div class="line">	static String stringOp(StringFunc sf,String s)</div><div class="line">	&#123;</div><div class="line">		return sf.func(s);</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		String inStr = &quot;lambda add power to Java&quot;;</div><div class="line">		String outStr;</div><div class="line">		</div><div class="line">		outStr = stringOp(MyStringOps::strReverse,inStr);</div><div class="line">		</div><div class="line">		System.out.println(&quot;Original string: &quot;+inStr);</div><div class="line">		System.out.println(&quot;String reserved: &quot;+outStr);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
Original string: lambda add power to Java
String reserved: avaJ ot rewop dda adbmal

在程序中，特别注意下面这行代码：

outStr = stringOp(MyStringOps::strReverse,inStr);

这里，将对MyStringOps内声明的静态方法strReverse()的引用传递给stringOp()方法的第一个参数。可以这么做，因为
strReverse与StringFunc函数式接口兼容。因此，表达式MyStringOps::strReverse的计算结果为对象引用，其中，
strReverse提供了StringFunc的func()方法的实现。 
</code></pre><p><strong>15.7.2 实例方法的方法引用</strong></p>
<pre><code>要传递对某个对象的实例方法的引用，需要使用下面的基本语法：

objRef::methodName

可以看出，这种语法与用于静态方法的语法类似，只不过这里使用对象引用而不是类名。下面使用实例方法引用重写了前面的程序：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div></pre></td><td class="code"><pre><div class="line">interface StringFunc</div><div class="line">&#123;</div><div class="line">	String func(String n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class MyStringOps</div><div class="line">&#123;</div><div class="line">	String strReverse(String str)</div><div class="line">	&#123;</div><div class="line">		String result = &quot;&quot;;</div><div class="line">		int i;</div><div class="line">		</div><div class="line">		for(i=str.length()-1; i&gt;=0; i--)</div><div class="line">		&#123;</div><div class="line">			result += str.charAt(i);</div><div class="line">		&#125;</div><div class="line">		</div><div class="line">		return result;</div><div class="line">	&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class MethodRefDemo2</div><div class="line">&#123;</div><div class="line">	static String stringOp(StringFunc sf,String s)</div><div class="line">	&#123;</div><div class="line">		return sf.func(s);</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		String inStr =&quot;lambda add power to Java&quot;;</div><div class="line">		String outStr;</div><div class="line">		</div><div class="line">		MyStringOps strOps = new MyStringOps();</div><div class="line">		</div><div class="line">		outStr = stringOp(strOps::strReverse,inStr);</div><div class="line">		</div><div class="line">		System.out.println(&quot;Original string: &quot;+inStr);</div><div class="line">		System.out.println(&quot;String reserved: &quot;+outStr);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>这个程序产生的输出与上一个版本相同。

也可以指定一个实例方法，使其能够用于给定类的任何对象而不仅指定对象。此时需要像下面这样创建方法引用：

ClassName::instanceMethodName

这里使用了类的名称，而不是具体的对象，尽管指定的是实例方法。使用这种形式时，函数式接口的第一个参数匹配调用对象，第二个参数匹配方法指定的参数。

下面是一个例子。它定义了一个方法counter()，用于统计某个数组中，满足函数式接口MyFunc的fun()方法定义的条件的对象个数。本例中，它统计HighTemp类的实例个数。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div></pre></td><td class="code"><pre><div class="line">interface MyFunc&lt;T&gt;</div><div class="line">&#123;</div><div class="line">	boolean func(T v1,T v2);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class HighTemp</div><div class="line">&#123;</div><div class="line">	private int hTemp;</div><div class="line">	</div><div class="line">	HighTemp(int ht)</div><div class="line">	&#123;</div><div class="line">		hTemp = ht;</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	boolean sameTemp(HighTemp ht2)</div><div class="line">	&#123;</div><div class="line">		return hTemp = ht2.hTemp;</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	boolean lessThanTemp(HighTemp ht2)</div><div class="line">	&#123;</div><div class="line">		return hTemp &lt; ht2.hTemp;</div><div class="line">	&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class InstanceMethWithObjectRefDemo</div><div class="line">&#123;</div><div class="line">	static &lt;T&gt; int counter(T[] vals,MyFunc&lt;T&gt; f,T v)</div><div class="line">	&#123;</div><div class="line">		int count = 0;</div><div class="line">		</div><div class="line">		for(int i=0; i&lt;vals.length; i++)</div><div class="line">		&#123;</div><div class="line">			if(f.func(vals[i],v)) count++;</div><div class="line">		&#125;</div><div class="line">		</div><div class="line">		return count;</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		int count;</div><div class="line">		</div><div class="line">		HighTemp[] weekDayHighs = &#123;</div><div class="line">				new HighTemp(89),new HighTemp(82),</div><div class="line">				new HighTemp(90),new HighTemp(89),</div><div class="line">				new HighTemp(89),new HighTemp(91),</div><div class="line">				new HighTemp(84),new HighTemp(83)&#125;;</div><div class="line">				</div><div class="line">		cout = counter(weekDayHighs,HighTemp::sameTemp,new HighTemp(89));</div><div class="line">		System.out.println(cout+&quot; days had a high of 89&quot;);</div><div class="line">		</div><div class="line">		HighTemp[] weekDayHighs2 = &#123;</div><div class="line">				new HighTemp(31),new HighTemp(12),</div><div class="line">				new HighTemp(24),new HighTemp(19),</div><div class="line">				new HighTemp(18),new HighTemp(12),</div><div class="line">				new HighTemp(-1),new HighTemp(13)&#125;;</div><div class="line">		</div><div class="line">		cout = counter(weekDayHighs2,HighTemp::sameTemp,new HighTemp(12));</div><div class="line">		System.out.println(count+&quot; days had a high of 12&quot;);</div><div class="line">		</div><div class="line">		cout = counter(weekDayHighs,HighTemp::lessThanTemp,new HighTemp(89));</div><div class="line">		System.out.println(count+&quot; days had a high less than 89&quot;);</div><div class="line">		</div><div class="line">		count = counter(weekDayHighs2,HighTemp::lessThanTemp,new HighTemp(19));</div><div class="line">		System.out.println(count+&quot; days had a high of less than 19&quot;);</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
3 days had a high of 89 
2 days had a high of 12 
3 days had a high less than 89 
5 days had a hign less than 19 

在这个程序中，注意HighTemp有两个实例方法：someTemp()和lessThanTemp()。如果两个HighTemp对象包含相同的温度，sameTemp()方法返回true。如果调用对象的温度小于被传递的对象的温度，lessThanTemp()方法返回true。这两个方法都有一个HighTemp类型的参数，并且都返回布尔结果。因此，这两个方法都与MyFunc函数式接口兼容，因为调用对象类型可以映射到func()的第一个参数，传递的实参可以映射到func()的第二个参数。因此，当下面的表达式：

HighTemp::sameTemp

被传递给counter()方法时，会创建函数式接口的一个实例，其中第一个参数的参数类型就是实例方法的调用对象的类型，也就是HighTemp。第二个参数的类型也是HighTemp，因为这是sameTemp()方法的参数。对于lessThanTemp()，这也是成立的。

另外一点，通过使用super，可以引用方法的超类版本。如下所示：

super::name

方法的名称由name指定。

备注：
上面程序中函数式接口中的函数boolean func(T v1,T v2)中含有两个参数，而HighTemp中函数sameTemp(HighTemp ht2)含有一个参数，但是能够兼容的原因是：
其实HighTemp类中的sameTemp(HighTemp ht2)其实包含两个参数，默认隐藏调用这个函数的引用this。
故，当使用类的实例方法作为方法引用时，函数式接口的第一个参数匹配类的实例方法的调用对象，第二个参数才匹配方法指定的参数。
</code></pre><p><strong>15.7.3 泛型中的方法引用</strong></p>
<pre><code>在泛型类或泛型方法中，也可以使用方法引用。例如，分析下面程序：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line">interface MyFunc&lt;T&gt;</div><div class="line">&#123;</div><div class="line">	int func(T[] vals,T v);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class MyArrayOps</div><div class="line">&#123;</div><div class="line">	static &lt;T&gt; int countMatching(T[] vals,T v)</div><div class="line">	&#123;</div><div class="line">		int count = 0;</div><div class="line">	</div><div class="line">		for(int i=0; i&lt;vals.length; i++)</div><div class="line">		&#123;</div><div class="line">			if(vals[i] == v) count++;</div><div class="line">		&#125;</div><div class="line">	</div><div class="line">		return count;</div><div class="line">	&#125;	</div><div class="line">&#125;</div><div class="line"></div><div class="line">class GenericMethodRefDemo</div><div class="line">&#123;</div><div class="line">	static&lt;T&gt; int myOp(MyFunc&lt;T&gt; f,T[] vals,T v)</div><div class="line">	&#123;</div><div class="line">		return f.func(vals,v);</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	Integer[] vals = &#123;1,2,3,4,2,3,4,4,5&#125;;</div><div class="line">	String[] strs = &#123;&quot;One&quot;,&quot;Two&quot;,&quot;Three&quot;,&quot;Two&quot;&#125;;</div><div class="line">	int count;</div><div class="line">	</div><div class="line">	count = myOp(MyArrayOps::&lt;Integer&gt;countMatching,vals,4);</div><div class="line">	System.out.println(&quot;vals contains &quot;+count+&quot; 4s&quot;);</div><div class="line">	</div><div class="line">	count = myOp(MyArrayOps::&lt;String&gt;countMatching,strs,&quot;Two&quot;);</div><div class="line">	System.out.println(&quot;strs contains &quot;+count+&quot; Twos&quot;);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
vals contains 3 4s
strs contains 2 Twos

在程序中，MyArrayOps是非泛型类，包含泛型方法countMatching()。该方法返回数组中与指定值匹配的元素的个数。注意这里如何指定泛型类型参数。例如，在main()方法中，对countMatching()方法的第一次调用如下所示：

count = myOp(MyArrayOps::&lt;Integer&gt;countMatching,vals,4);

这里传递了类型参数Integer。注意，参数传递发生在::的后面。这种语法可以推广。当把泛型方法指定为方法引用时，类型参数出现在::之后、方法名之前。但是，需要指出的是，在这种情况(和其它许多情况)下，并非必须显示指定类型参数，因为类型参数会被自动推断得出。对于指定泛型类的情况，类型参数位于类名的后面、::的前面。

前面的例子显示了使用方法引用的机制，但是没有展现它们真正的优势。方法引用能够一展拳脚的一处地方是在于集合框架一起使用时。在第18章详细介绍。

例如：找到集合中最大元素的一种方法是使用Collections类定义的max()方法。对于这里使用的max()版本，必须传递一个集合引用，以及一个实现了Comparator&lt;T&gt;接口的对象的实例。Comparator&lt;T&gt;接口指定如何比较两个对象，它只定义了抽象方法compare()，该方法接受两个参数，其类型均为要比较的对象的类型。如果第一个参数大于第二个参数，该方法返回一个正数；如果两个参数相等，返回0；如果第一个参数小于第二个参数，返回一个负数。

过去，要在max()方法中使用用户定义的对象，必须首先通过一个类显式实现Comparator&lt;T&gt;接口，然后创建该类的一个实例，通过这种方法获得Comparator&lt;T&gt;接口的一个实例，然后，把这个实例作为比较器传递给max()方法。在JDK 8中，现在可以简单地将比较方法的引用传递给max()方法，因为这将自动实现比较器。

下面的简单的示例显示了这个过程。该例创建MyCLass对象的一个ArrayList，然后找到列表中具有最大值的对象(这是由比较方法定义的)。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line">import java.util.*;</div><div class="line"></div><div class="line">class MyClass</div><div class="line">&#123;</div><div class="line">	private int val;</div><div class="line">	</div><div class="line">	MyClass(int v)&#123;val = v;&#125;</div><div class="line">	</div><div class="line">	int getValue()&#123;return val;&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class UseMethodRef</div><div class="line">&#123;</div><div class="line">	static int compareMC(MyClass a,MyClass b)</div><div class="line">	&#123;</div><div class="line">		return a.getValue()-b.getValue();</div><div class="line">	&#125;</div><div class="line">	</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		ArrayList&lt;MyClass&gt; a1 = new ArrayList&lt;MyClass&gt;();</div><div class="line">		</div><div class="line">		a1.add(new MyClass(1));</div><div class="line">		a1.add(new MyClass(4));</div><div class="line">		a1.add(new MyClass(2));</div><div class="line">		a1.add(new MyClass(9));</div><div class="line">		a1.add(new MyClass(3));</div><div class="line">		a1.add(new MyClass(7));</div><div class="line">		</div><div class="line">		//UseMethodRef::compareMC生成了抽象接口Comparator定义的compare()方法的实例。</div><div class="line">		MyClass maxValObj = Collections.max(a1,UseMethodRef::compareMC);</div><div class="line">		</div><div class="line">		System.out.println(&quot;Maximum value is: &quot;+maxValObj.getValue());</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
Maximum value is: 9 

在程序中，注意MyClass即没有定义自己的比较方法，也没有实现Comparator接口。但是，通过调用max()方法，仍然可以获得MyClass对象列表中的最大值，这是因为UseMethodRef定义了静态方法compareMC()，它与Comparator定义的compare()方法兼容。因此，没哟必要显式的实现Comparator接口并创建其实例。
</code></pre><p><strong>15.8 构造函数引用</strong></p>
<pre><code>与创建方法引用相似，可以创建构造函数的引用。所需语法的一般形式如下所示：

className::new 

可以把这个引用赋值给定义的方法与构造函数兼容的任何函数式接口的引用。下面是一个例子：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">interface MyFunc</div><div class="line">&#123;</div><div class="line">	MyClass func(int n);</div><div class="line">&#125;</div><div class="line"></div><div class="line">class MyClass</div><div class="line">&#123;</div><div class="line">	private int val;</div><div class="line">	</div><div class="line">	MyClass(int v)&#123;val = v;&#125;</div><div class="line">	</div><div class="line">	MyClass()&#123;val = 0;&#125;</div><div class="line">	</div><div class="line">	int getValue()&#123;return val;&#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">class ConstructorRefDemo</div><div class="line">&#123;</div><div class="line">	MyFunc myClassCons = MyClass::new;</div><div class="line">	</div><div class="line">	MyClass mc = myClassCons.func(100);</div><div class="line">	System.out.println(&quot;val in mc is: &quot;+mc.getValue());</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>输出：
val in mc is: 100 

在程序中，注意MyFunc的func()方法返回MyClass类的引用，并且有一个int类型的参数。接下来，注意MyClass定义了两个构造函数。第一个构造函数指定了一个int类型的参数，第二个构造函数是无参构造函数。现在，分析下面这行代码：

MyFunc myClassCons = MyClass::new;

这里，表达式MyClass::new创建了对MyClass构造函数的引用。在本例中，因为为MyFunc的func()方法接受了一个int类型的参数，所以被引用的构造函数是MyClass(int v),它是正确匹配的构造函数。还要注意，对这个构造函数的引用被赋值给
了名为myClassCons的MyFunc引用。这条语句执行后，可以使用myClassCons来创建MyClass的一个实例，如下面这行代码所示：

MyClass mc = myClassCons.func(100);

实质上，myClassCons成了调用MyClass(int v)的另一种方式。
</code></pre><p><strong>15.9 预定义的函数式接口</strong></p>
<pre><code>直到现在，本章中的实例都定义了自己的函数式接口，以便清晰地演示lambda表达式和函数式接口背后的基本概念。但是很多时候，并不需要自己定义函数式接口，因为JDK 8中包含了新包java.util.function，其中提供了一些预定义的函数式
接口。在第2部分详细讨论，这里只做简单简介。

java.util.function包中提供的一些预定义函数式接口：UnaryOperator&lt;T&gt;,BinaryOperator&lt;T&gt;,Consumer&lt;T&gt;,Supplier&lt;T&gt;,Function&lt;T,R&gt;,Predicate&lt;T&gt;。

Function&lt;T,R&gt;:对类型为T的对象应用操作，并返回结果。结果是类型为R的对象。包含的方法名为apply()。

下面的程序通过使用Function接口重写前面的BlocklambdaDemo示例，演示了Function接口的实际应用。BlocklambdaDemo示例通过实现了一个阶乘，演示了块lambda。该示例创建了自己的函数式接口NumericFunc，但其实也可以使用内置的Function接口中定义的抽象函数apply()，如程序的下面这个版本所示：
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line">import java.util.function.Function;</div><div class="line"></div><div class="line">class UseFunctionInterfaceDemo</div><div class="line">&#123;</div><div class="line">	public static void main(String[] args)</div><div class="line">	&#123;</div><div class="line">		Function&lt;Integer,Integer&gt; factorial = (n)-&gt;</div><div class="line">		&#123;</div><div class="line">			int result = 1;</div><div class="line">			</div><div class="line">			for(int i=1; i&lt;=n; i++)</div><div class="line">			&#123;</div><div class="line">				result = result*i;</div><div class="line">			&#125;</div><div class="line">			</div><div class="line">			return result;</div><div class="line">		&#125;;</div><div class="line">		</div><div class="line">		System.out.println(&quot;The factorial of 3 is &quot;+factorial.apply(3));</div><div class="line">	&#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<pre><code>这个版本产生的输出与前一个版本相同。
Function&lt;T,R&gt;是预定义的函数式接口，抽象函数为apply()，故不需要自己定义函数式接口。
</code></pre><p>出自：《Java 8编程参考官方教程(第9版)》</p>
</the>
      
    </div>
    
  </div>
  
    
    <div class="copyright">
        <p><span>本文标题:</span><a href="/Programming/Java/Java之lambda表达式/">Java之lambda表达式</a></p>
        <p><span>文章作者:</span><a href="/" title="回到主页">FreeShow</a></p>
        <p><span>发布时间:</span>2016-07-23, 23:06:29</p>
        <p><span>最后更新:</span>2017-03-28, 16:06:44</p>
        <p>
            <span>原始链接:</span><a class="post-url" href="/Programming/Java/Java之lambda表达式/" title="Java之lambda表达式">https://freeshow.github.io/Programming/Java/Java之lambda表达式/</a>
            <span class="copy-path" data-clipboard-text="原文: https://freeshow.github.io/Programming/Java/Java之lambda表达式/　　作者: FreeShow" title="点击复制文章链接"><i class="fa fa-clipboard"></i></span>
            <script> var clipboard = new Clipboard('.copy-path'); </script>
        </p>
        <p>
            <span>许可协议:</span><i class="fa fa-creative-commons"></i> <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" title="CC BY-NC-SA 4.0 International" target = "_blank">"署名-非商用-相同方式共享 4.0"</a> 转载请保留原文链接及作者。
        </p>
    </div>



    <nav id="article-nav">
        
            <div id="article-nav-newer" class="article-nav-title">
                <a href="/Programming/Java/Java之I-O以及其它主题/">
                    Java之I/O以及其它主题
                </a>
            </div>
        
        
            <div id="article-nav-older" class="article-nav-title">
                <a href="/Programming/Java/Java之字符串处理/">
                    Java之字符串处理
                </a>
            </div>
        
    </nav>

  
</article>

    <div id="toc" class="toc-article">
        <strong class="toc-title">文章目录</strong>
        
            
        
    </div>
    <style>
        .left-col .switch-btn,
        .left-col .switch-area {
            display: none;
        }
        .toc-level-3 i,
        .toc-level-3 ol {
            display: none !important;
        }
    </style>

    <input type="button" id="tocButton" value="隐藏目录"  title="点击按钮隐藏或者显示文章目录">

    <script>
        yiliaConfig.toc = ["隐藏目录", "显示目录", !!"false"];
    </script>



    
<div class="share">
    
        <div class="bdsharebuttonbox">
            <a href="#" class="fa fa-twitter bds_twi" data-cmd="twi" title="分享到推特"></a>
            <a href="#" class="fa fa-weibo bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
            <a href="#" class="fa fa-qq bds_sqq" data-cmd="sqq" title="分享给 QQ 好友"></a>
            <a href="#" class="fa fa-files-o bds_copy" data-cmd="copy" title="复制网址"></a>
            <a href="#" class="fa fa fa-envelope-o bds_mail" data-cmd="mail" title="通过邮件分享"></a>
            <a href="#" class="fa fa-weixin bds_weixin" data-cmd="weixin" title="生成文章二维码"></a>
            <a href="#" class="fa fa-share-alt bds_more" data-cmd="more"></i></a>
        </div>
        <script>
            window._bd_share_config={
                "common":{"bdSnsKey":{},"bdText":"Java之lambda表达式　| FreeShow　","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"24"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
        </script>
    

    
</div>







    
      <div class="duoshuo" id="comments">
    <div id="comment-box" ></div>
    <div class="ds-thread" id="ds-thread" data-thread-key="Programming/Java/Java之lambda表达式/" data-title="Java之lambda表达式" data-url="https://freeshow.github.io/Programming/Java/Java之lambda表达式/"></div>
    <script>
        var duoshuoQuery = {short_name:"freeshowgithub"};
        var loadComment = function(){
            var d = document, s = d.createElement('script');
            s.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
            s.async = true; s.charset = 'UTF-8';
            (d.head || d.body).appendChild(s);
        }

        
    </script>
    
    <script> loadComment(); </script>

</div>
    




    <div class="scroll" id="post-nav-button">
        
            <a href="/Programming/Java/Java之I-O以及其它主题/" title="上一篇: Java之I/O以及其它主题">
                <i class="fa fa-angle-left"></i>
            </a>
        

        <a title="文章列表"><i class="fa fa-bars"></i><i class="fa fa-times"></i></a>

        
            <a href="/Programming/Java/Java之字符串处理/" title="下一篇: Java之字符串处理">
                <i class="fa fa-angle-right"></i>
            </a>
        
    </div>

    <ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/Hadoop分布式集群安装/">Hadoop分布式集群安装</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hive/Hive应用实例：WordCount/">Hive应用实例：WordCount</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hive/Hive安装/">Hive安装</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/Windows下使用eclipse插件运行自己的MapReduce程序/">Windows下使用Eclipse插件运行自己的MapReduce程序</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/MapReduce之去重计数类应用/">MapReduce之去重计数类应用</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/MapReduce之简单排序类应用/">MapReduce之简单排序类应用</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/MapReduce之连接操作类应用/">MapReduce之连接操作类应用</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/MapReduce之计数类应用/">MapReduce之计数类应用</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/MapReduce之二次排序类应用/">MapReduce之二次排序类应用</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/MapReduce之倒排索引类应用/">MapReduce之倒排索引类应用</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/HDFS Java API/">HDFS Java API</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Kafka/Kafka集群安装/">Kafka集群安装</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Hadoop/Windows下使用eclipse编译打包运行自己的MapReduce程序 Hadoop2.6.0/">Windows下使用eclipse编译打包运行自己的MapReduce程序 Hadoop2.6.0</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/ZooKeeper/ZooKeeper集群安装/">ZooKeeper集群安装</a></li><li class="post-list-item"><a class="post-list-link" href="/BigData/Spark/Spark安装和集群部署/">Spark安装和集群部署</a></li><li class="post-list-item"><a class="post-list-link" href="/Comprehensive/BuildBlog/GitHub Pages + Hexo搭建个人博客/">GitHub Pages + Hexo搭建个人博客</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫实例：登录豆瓣并修改签名/">Python爬虫实例：登录豆瓣并修改签名</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫实例：用requests重构豆瓣热播电影爬虫/">Python爬虫实例：用requests重构豆瓣热播电影爬虫</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫实例：豆瓣热播电影/">Python爬虫实例：豆瓣热播电影（urllib+urllib2）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫之requests介绍/">Python爬虫之requests介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫之urllib2介绍/">Python爬虫之urllib2介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫之urllib介绍/">Python爬虫之urllib介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Cookie介绍/">Cookie介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫实例：从百度图片下载壁纸/">Python爬虫实例：从百度图片下载壁纸</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python线程/">Python线程</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/XPath与多线程爬虫/">XPath与多线程爬虫</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python之正则表达式/">Python之正则表达式</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫实例：唐诗三百首/">Python爬虫实例：唐诗三百首</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python爬虫进阶/">Python爬虫进阶</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python初步使用scrapy/">Python初步使用Scrapy</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python开发简单爬虫之实战演练/">Python开发简单爬虫之实战演练</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Python/Python开发简单爬虫之爬虫介绍（一）/">Python开发简单爬虫之爬虫介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/FreeSwitch/FreeSwitch压力测试/">FreeSwitch压力测试</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/FreeSwitch/FreeSwitch使用mod-xml-curl提供动态用户管理/">FreeSwitch使用mod_xml_curl提供动态用户管理</a></li><li class="post-list-item"><a class="post-list-link" href="/Comprehensive/Tools/Win10下MarkdownPad安装及问题/">Win10下MarkdownPad安装及问题</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Ubuntu14-04安装Apache-php5-mysql-phpmyadmin/">Ubuntu14.04安装Apache+php5+mysql+phpmyadmin</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/C/Linux下C语言入门准备/">Linux下C语言入门准备</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/vi编辑器/">vi编辑器</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell简单介绍/">Shell简单介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/linux基础（四）/">linux基础（四）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Linux基础（三）/">Linux基础（三）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Linux基础（二）/">Linux基础（二）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Ubuntu Server 14.04 静态IP简单配置/">Ubuntu Server 14.04 静态IP简单配置</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Linux基础（一）/">Linux基础（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之Handler详解（一）-关联到UI线程/">Android之Handler详解（一）---关联到UI线程</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之Handler详解（二）-关联到非UI线程/">Android之Handler详解（二）---关联到非UI线程</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之更新UI的方法/">Android之更新UI的方法</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之延迟执行某个任务/">Android之延迟执行某个任务</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/AndroidStudio之环境设置 /">初次安装AndroidStudio之环境设置</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/java里如何正确计算检验和/">java里如何正确计算检验和</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之AsyncTask介绍/">Android之AsyncTask介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之Fragment（一）-简介/">Android之Fragment（一）--简介</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之Fragment（二）-使用/">Android之Fragment（二）--使用</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之Fragment（三）-生命周期与回退栈/">Android之Fragment（三）--生命周期与回退栈</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java运行时多态性：继承和接口的实现/">Java运行时多态性：继承和接口的实现</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之Fragment（四）-Fragment与Activity通讯/">Android之Fragment（四）--Fragment与Activity通讯</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之RAM、ROM和SD卡/">Android之RAM、ROM和SD卡</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之使用全局变量的两种方法/">Android之使用全局变量的两种方法</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之数据存储-SharedPreference/">Android之数据存储--SharedPreference</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之数据存储-File内部存储/">Android之数据存储--File内部存储</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之数据存储-外部存储（SD卡）/">Android之数据存储--外部存储（SD卡）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之音频播放（MediaPlayer和SoundPool）/">Android之音频播放（MediaPlayer和SoundPool）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之话筒、听筒、扬声器/">Android之话筒、听筒、扬声器</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之数据存数-SQLite数据库/">Android之数据存数--SQLite数据库</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之AdapterView及子类/">Android之AdapterView及子类</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之ListView和ListActivity-ArrayAdapter/">Android之ListView和ListActivity--ArrayAdapter</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之列表视图（LitView）-SimpleAdapter/">Android之列表视图（LitView）--SimpleAdapter</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之列表视图（LstView）-BaseAdapter/">Android之列表视图（LstView）--BaseAdapter</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之自动完成文本框（AutoCompleteTextView）/">Android之自动完成文本框（AutoCompleteTextView）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之网格视图（GridView）/">Android之网格视图（GridView）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之可扩展的列表组件（ExpandableListView）/">Android之可扩展的列表组件（ExpandableListView）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/ListView的性能优化之convertView和viewHolder/">ListView的性能优化之convertView和viewHolder</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/android-layout-weight的真实含义/">android:layout_weight的真实含义</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Android/Android之使用9Patch图片作为背景/">Android之使用9Patch图片作为背景</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java综述/">Java综述</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之数据类型、变量和数组/">Java之数据类型、变量和数组</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之运算符/">Java之运算符</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之控制语句/">Java之控制语句</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之类/">Java之类</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之方法和类的深入分析/">Java之方法和类的深入分析</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之继承/">Java之继承</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之包和接口/">Java之包和接口</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之异常处理/">Java之异常处理</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之多线程编程/">Java之多线程编程</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之枚举、自动装箱与注解（元数据）/">Java之枚举、自动装箱与注解（元数据）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之I-O以及其它主题/">Java之I/O以及其它主题</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之lambda表达式/">Java之lambda表达式</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之字符串处理/">Java之字符串处理</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Java/Java之集合框架/">Java之集合框架</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Scala/Scala访问控制修饰符/">Scala访问控制修饰符</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Scala/Scala类/">Scala类</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Scala/Scala函数（一）/">Scala函数（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Scala/Scala函数（二）/">Scala函数（二）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Scala/Scala单例对象/">Scala单例对象</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/使用WebRTC搭建前端视频聊天室——信令篇/">使用WebRTC搭建前端视频聊天室——信令篇</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/使用WebRTC搭建前端视频聊天室——数据通道篇/">使用WebRTC搭建前端视频聊天室——数据通道篇</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/使用WebRTC搭建前端视频聊天室——点对点通信篇/">使用WebRTC搭建前端视频聊天室——点对点通信篇</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/WebRTC工作流程/">WebRTC工作流程</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/Android之WebRTC实现/">Android之WebRTC实现</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/Android之WebRTC介绍（二）/">Android之WebRTC介绍（二）</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/Android之WebRTC介绍（一）/">Android之WebRTC介绍（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/WebRTC之turn服务器搭建/">WebRTC之turn服务器搭建</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/XMPP/openfire之SSL认证/">openfire之SSL认证</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/XMPP/基于openfire-smack开发Android即时聊天应用-一-用户注册、登陆、修改密码、注销等/">基于openfire+smack开发Android即时聊天应用[一]-用户注册、登陆、修改密码、注销等</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/OpenSIPs/ubuntu下opensips安装配置/">ubuntu下opensips安装配置</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/计算机是如何启动的？/">计算机是如何启动的？</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Linux的启动流程/">Linux的启动流程</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/XMPP/Smack Message属性扩展---添加自定义元素(标签)/">Smack Message属性扩展--添加自定义元素（标签）</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/DataStructure/线性表-顺序表/">线性表---顺序表</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/SIP/SIP对话流程/">SIP对话流程</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/SIP/SIP服务器类型/">SIP服务器类型</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/SIP/SIP注册过程/">SIP注册过程</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/OpenSIPs/openSIPS路由类型/">openSIPS路由类型</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/OpenSIPs/opensips函数/">opensips函数</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/SIP/SIP路由字段和机理/">SIP路由字段和机理</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/OpenSIPs/opensips-csipsimple出现的各种问题/">opensips+csipsimple出现的各种问题</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/OpenSIPs/opensips介绍/">opensips介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（八）-输入输出重定向、文件包含/">Shell编程（八）---输入输出重定向、文件包含</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（七）-函数/">Shell编程（七）---函数</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（六）-循环/">Shell编程（六）---循环</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（五）-if、case/">Shell编程（五）---if、case</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（四）-echo、printf/">Shell编程（四）---echo、printf</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（三）-字符串、数组/">Shell编程（三）---字符串、数组</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（二）-替换、运算符、注释/">Shell编程（二）---替换、运算符、注释</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Shell/Shell编程（一）/">Shell编程（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/WebRTC/使用WebRTC搭建前端视频聊天室——入门篇/">使用WebRTC搭建前端视频聊天室——入门篇</a></li><li class="post-list-item"><a class="post-list-link" href="/Comprehensive/BuildBlog/更改Yelee主题标签云为球形标签云/">更改Yelee主题标签云为球形标签云</a></li><li class="post-list-item"><a class="post-list-link" href="/Communication/FreeSwitch/FreeSwitch安装文档/">FreeSwitch安装文档</a></li><li class="post-list-item"><a class="post-list-link" href="/Comprehensive/BuildBlog/Hexo主题Yelee介绍/">Hexo主题Yelee介绍</a></li><li class="post-list-item"><a class="post-list-link" href="/Programming/Linux/Ubuntu14-04安装JDK与配置环境变量/">Ubuntu14.04安装JDK与配置环境变量</a></li></ul>




    <script>
        
    </script>
</div>
      <footer id="footer">
    <div class="outer">
        <div id="footer-info">
            <div class="footer-left">
                <i class="fa fa-copyright"></i> 
                2016-2017 FreeShow
            </div>
            <div class="footer-right">
                <a href="http://hexo.io/" target="_blank" title="快速、简洁且高效的博客框架">Hexo</a>  Theme <a href="https://github.com/MOxFIVE/hexo-theme-yelee" target="_blank" title="简而不减 Hexo 双栏博客主题  v3.5">Yelee</a> by MOxFIVE <i class="fa fa-heart animated infinite pulse"></i>
            </div>
        </div>
        
            <div class="visit">
                
                    <span id="busuanzi_container_site_pv" style='display:none'>
                        <span id="site-visit" title="本站到访数"><i class="fa fa-user" aria-hidden="true"></i><span id="busuanzi_value_site_uv"></span>
                        </span>
                    </span>
                
                
                    <span>| </span>
                
                
                    <span id="busuanzi_container_page_pv" style='display:none'>
                        <span id="page-visit"  title="本页阅读量"><i class="fa fa-eye animated infinite pulse" aria-hidden="true"></i><span id="busuanzi_value_page_pv"></span>
                        </span>
                    </span>
                
            </div>
        
    </div>
</footer>
    </div>
    
    <script src="/js/GithubRepoWidget.js"></script>

<script data-main="/js/main.js" src="//cdn.bootcss.com/require.js/2.2.0/require.min.js"></script>

    <script>
        $(document).ready(function() {
            var iPad = window.navigator.userAgent.indexOf('iPad');
            if (iPad > -1 || $(".left-col").css("display") === "none") {
                var bgColorList = ["#9db3f4", "#414141", "#e5a859", "#f5dfc6", "#c084a0", "#847e72", "#cd8390", "#996731"];
                var bgColor = Math.ceil(Math.random() * (bgColorList.length - 1));
                $("body").css({"background-color": bgColorList[bgColor], "background-size": "cover"});
            }
            else {
                var backgroundnum = 5;
                var backgroundimg = "url(/background/bg-x.jpg)".replace(/x/gi, Math.ceil(Math.random() * backgroundnum));
                $("body").css({"background": backgroundimg, "background-attachment": "fixed", "background-size": "cover"});
            }
        })
    </script>





    <script type="text/x-mathjax-config">
MathJax.Hub.Config({
    tex2jax: {
        inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
        processEscapes: true,
        skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    }
});

MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
        all[i].SourceElement().parentNode.className += ' has-jax';                 
    }       
});
</script>

<script src="//cdn.bootcss.com/mathjax/2.6.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>


<div class="scroll" id="scroll">
    <a href="#" title="返回顶部"><i class="fa fa-arrow-up"></i></a>
    <a href="#comments" onclick="load$hide();" title="查看评论"><i class="fa fa-comments-o"></i></a>
    <a href="#footer" title="转到底部"><i class="fa fa-arrow-down"></i></a>
</div>
<script>
    // Open in New Window
    
        var oOpenInNew = {
             github: ".github-widget a", 
            
            
            
            
            
             archives: ".archive-article-title", 
             miniArchives: "a.post-list-link", 
            
             friends: "#js-friends a", 
             socail: ".social a" 
        }
        for (var x in oOpenInNew) {
            $(oOpenInNew[x]).attr("target", "_blank");
        }
    
</script>

<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js">
</script>
  </div>
</body>
</html>